package com.tangsm.spring.boot.word.to.file.utli;

import cn.afterturn.easypoi.word.WordExportUtil;
import com.tangsm.spring.boot.word.to.file.entity.Person;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.docx4j.Docx4J;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFont;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.wml.RFonts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * Word文档处理工具类
 *
 * @author tangyb
 */
public class DocUtils {
    private static final Logger log = LoggerFactory.getLogger(DocUtils.class);

    /**
     * word文件后缀
     */
    public static final String SUFFIX_WORD = ".docx";

    /**
     * pdf文件后缀
     */
    public static final String SUFFIX_PDF = ".pdf";

    /**
     * 根据word模板生成文件
     *
     * @param templatePath 模板路径
     * @param temDir       生成临时文件存放地址
     * @param fileName     文件名称
     * @param params       参数
     * @return 文件
     */
    public static boolean exportWord(String templatePath, String temDir, String fileName, Map<String, Object> params) {
        log.info("根据word模板生成文件开始...");
        log.info("模板路径：{}", templatePath);
        log.info("生成临时文件存放地址：{}", temDir);
        log.info("文件名称：{}", fileName);
        log.info("参数：{}", params);

        if (StringUtils.isBlank(templatePath)) {
            log.info("模板路径不能为空");
            return false;
        }
        if (StringUtils.isBlank(temDir)) {
            log.info("生成临时文件存放地址不能为空");
            return false;
        }
        if (StringUtils.isBlank(fileName)) {
            log.info("文件名称不能为空");
            return false;
        }
        if (!fileName.toLowerCase(Locale.ROOT).endsWith(SUFFIX_WORD)) {
            log.info("文件名后缀必须是docx格式");
            return false;
        }

        temDir = formatPath(temDir);

        // 校验并创建文件夹
        foundPath(temDir);

        // 临时文件全路径
        String tmpPath = temDir + fileName;
        FileOutputStream fos = null;
        try {
            XWPFDocument doc = WordExportUtil.exportWord07(templatePath, params);
            fos = new FileOutputStream(tmpPath);
            doc.write(fos);
            fos.close();
        } catch (IOException e) {
            log.error("根据word模板生成文件IO异常", e);
        } catch (Exception e) {
            log.error("EasyPoi处理异常", e);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        log.info("根据word模板生成文件完成...");
        return true;
    }

    /**
     * 格式化文件夹路径路径，统一'/'结尾
     *
     * @param path 文件夹路径路径
     * @return 文件夹路径路径
     */
    public static String formatPath(String path) {
        if (!path.endsWith("/") && !path.endsWith("\\")) {
            path = path + File.separator;
        }
        return path;
    }

    /**
     * 根据路径创建文件夹
     *
     * @param path 文件夹路径
     * @return 成功，失败
     */
    public static boolean foundPath(String path) {
        if (StringUtils.isBlank(path)) {
            log.info("文件夹路径不能为空");
            return false;
        }

        File file = new File(path);

        //根据文件夹路径创建文件夹
        if (!file.exists()) {
            return file.mkdirs();
        }

        return true;
    }

    /**
     * word 转 pdf
     *
     * @param wordPath  word文件路径
     * @param outFolder 输出文件夹
     * @param pdfName   输出pdf文件名称
     * @param fontPath  输出pdf文件名称
     */
    public static boolean worToPdf(String wordPath, String outFolder, String pdfName, String fontPath) {
        log.info("word 转 pdf 开始...");
        log.info("word文件路径：{}", wordPath);
        log.info("输出文件夹：{}", outFolder);
        log.info("输出pdf文件名称：{}", pdfName);
        if (StringUtils.isBlank(wordPath)) {
            log.info("word文件路径不能为空");
            return false;
        }
        if (StringUtils.isBlank(wordPath)) {
            log.info("输出文件夹不能为空");
            return false;
        }
        if (StringUtils.isBlank(pdfName)) {
            log.info("输出pdf文件名称不能为空");
            return false;
        }
        if (!pdfName.toLowerCase(Locale.ROOT).endsWith(SUFFIX_PDF)) {
            log.info("输出文件名称后缀必须为.pdf");
            return false;
        }

        // 格式化文件夹路径
        outFolder = formatPath(outFolder);

        // 创建文件夹
        foundPath(outFolder);

        // 输出文件路径
        String fileName = outFolder.concat(pdfName);


        OutputStream os = null;
        InputStream is = null;
        try {
            is = new FileInputStream(wordPath);
            WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(is);

            //  设置字体
            configSimSunFont(mlPackage, fontPath);
//            Mapper fontMapper = new IdentityPlusMapper();
//            fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
//            fontMapper.put("宋体", PhysicalFonts.get("SimSun"));
//            fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft Yahei"));
//            fontMapper.put("黑体", PhysicalFonts.get("SimHei"));
//            fontMapper.put("楷体", PhysicalFonts.get("KaiTi"));
//            fontMapper.put("新宋体", PhysicalFonts.get("NSimSun"));
//            fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
//            fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
//            fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB"));
//            fontMapper.put("仿宋", PhysicalFonts.get("FangSong"));
//            fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
//            fontMapper.put("幼圆", PhysicalFonts.get("YouYuan"));
//            fontMapper.put("华文宋体", PhysicalFonts.get("STSong"));
//            fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong"));
//            mlPackage.setFontMapper(fontMapper);

            // 创建 pdf 文件输出流
            os = new FileOutputStream(fileName);

            Docx4J.toPDF(mlPackage, os);
        } catch (FileNotFoundException e) {
            log.error("文件不存在异常", e);
            return false;
        } catch (Docx4JException e) {
            log.error("Docx4转换pdf异常", e);
            return false;
        } catch (Exception e) {
            log.error("其他未知异常", e);
            return false;
        } finally {
            // 删除临时文件
            File file = new File(wordPath);
            if (file.exists() && file.isFile()) {
                file.delete();
            }

            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

        log.info("word 转 pdf 完成...");
        return true;
    }

    /**
     * 为 {@link org.docx4j.openpackaging.packages.WordprocessingMLPackage} 配置中文字体
     *
     * @param mlPackage 文字处理机
     * @param fontPath  中文字体文件路径
     * @throws Exception 异常信息
     */
    public static void configSimSunFont(WordprocessingMLPackage mlPackage, String fontPath) throws Exception {
        Mapper fontMapper = new IdentityPlusMapper();
        log.debug("fontPath={}", fontPath);

        //加载字体文件（解决linux环境下无中文字体问题）
        String fontFamily = "SimSun";
        URI simsunUri = new URI(String.format("file:%s", fontPath));
        PhysicalFonts.addPhysicalFonts(fontFamily, simsunUri);
        PhysicalFont simsunFont = PhysicalFonts.get(fontFamily);

        log.debug("simsunFont.getName()={}", simsunFont.getName());

        fontMapper.put(fontFamily, simsunFont);

        mlPackage.setFontMapper(fontMapper);

        //设置文件默认字体
        RFonts rfonts = Context.getWmlObjectFactory().createRFonts();
        rfonts.setAsciiTheme(null);
        rfonts.setAscii(fontFamily);
        mlPackage.getMainDocumentPart()
                .getPropertyResolver()
                .getDocumentDefaultRPr()
                .setRFonts(rfonts);
    }

    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
        map.put("department", "Jee\r\ncg");
        map.put("person", "Jue\r\nYue");
        map.put("isDel", true);
        map.put("auditPerson", "JueYue");
        map.put("time", "2018/08/08");
        map.put("date", new Date());
        List<Person> list = new ArrayList<Person>();
        Person p = new Person();
        p.setName("小明");
        p.setTel("18711111111");
        p.setEmail("18711111111@\\r\\n139.com");
        list.add(p);
        p = new Person();
        p.setName("小红");
        p.setTel("18711111112");
        p.setEmail("18711111112@\r\n139.com");
        list.add(p);
        map.put("pList", list);

        if (DocUtils.exportWord("word/SimpleExcel.docx", "D:/test/", "中文报表.docx", map)) {
            DocUtils.worToPdf("D:/test/中文报表.docx", "D:/test/", "中文报表.pdf", "C:/Windows/Fonts/simsun.ttc");
        }
    }
}